package cagt.tools.standard;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;

/**
 * Tool for searching the longest sequence in the set of cards.
 * 
 * @author konrad
 * 
 */
public final class FigureSequenceFinder {
	private FigureSequenceFinder() {
	}

	/**
	 * Standard sequence of cards - without joker.
	 */
	public final static List<Figure> standardFigureOrder;

	static {
		// Prepare standard sequence
		List<Figure> sequence = new ArrayList<Figure>(Arrays.asList(Figure
				.values()));
		sequence.remove(Figure.Joker);
		standardFigureOrder = Collections.unmodifiableList(sequence);
	}

	/**
	 * Get the longest sequence using standard figure order. See {@link
	 * getLongestSequence()}
	 * 
	 * @param cardSet
	 *            Card set.
	 * @return Longest sequence of cards.
	 */
	public static List<StandardCard> getLongestSequence(
			final Set<StandardCard> cardSet) {
		return getLongestSequence(cardSet, standardFigureOrder);
	}

	/**
	 * Get the longest sequence using given figure order. See {@link
	 * getLongestSequence()}
	 * 
	 * @param cardSet
	 *            Card set.
	 * @param figureOrder
	 *            Figure order.
	 * @return Longest sequence of cards.
	 */
	public static List<StandardCard> getLongestSequence(
			final Set<StandardCard> cardSet, final List<Figure> figureOrder) {
		return getLongestSequence(
				cardSet,
				figureOrder,
				new StandardCardMultiComparator(figureOrder, null, false, false));
	}

	/**
	 * Get the longest sequence of cards using given figure order. Cards are
	 * sorted using the comparator given by the user and then their list is
	 * searched for sequence occurrence. Indexes of cards are taken from figure
	 * order list.
	 * 
	 * @param cardSet
	 *            Card set.
	 * @param figureOrder
	 *            Figure order.
	 * @param comparator
	 * 	
	 * @return Longest sequence of cards.
	 */
	public static List<StandardCard> getLongestSequence(
			final Set<StandardCard> cardSet, final List<Figure> figureOrder,
			final Comparator<StandardCard> comparator) {
		// Check
		if (cardSet == null || comparator == null) {
			throw new NullPointerException();
		}
		// Sort cards from card set
		List<StandardCard> cards = new ArrayList<StandardCard>(cardSet);
		Collections.sort(cards, comparator);
		// Result
		List<StandardCard> longest = new ArrayList<StandardCard>();
		List<StandardCard> current = new ArrayList<StandardCard>();
		Integer lastFigureInd = null;
		// Browse the cards list
		for (StandardCard card : cards) {
			// Get current card figure index
			int currentCardFigureIndex = figureOrder.indexOf(card.getFigure());
			// If current card's figure is not present in order - situation
			// should not be
			if (currentCardFigureIndex < 0) {
				throw new IllegalArgumentException(
						"Card set's card's figure is not present in figure order.");
			}
			if (lastFigureInd == null
					|| lastFigureInd + 1 == currentCardFigureIndex) {
				// If figure index is greater by 1 than last ones or there was
				// no card before - add card to current sequence
				current.add(card);
			} else if (lastFigureInd + 1 < currentCardFigureIndex) {
				// If figure index is greater by more than one the sequence is
				// completed - check if it is the longest
				if (current.size() > longest.size()) {
					longest = current;
				}
				current = new ArrayList<StandardCard>();
				current.add(card);
			} else if (lastFigureInd != currentCardFigureIndex) {
				throw new IllegalArgumentException(
						"Order of figures was not preserved - something gone wrong. "
								+ Arrays.toString(cards.toArray()));
			}
			// Note the last figure index
			lastFigureInd = currentCardFigureIndex;
		}
		// Check the current sequence
		if (current.size() > longest.size()) {
			longest = current;
		}
		return longest;
	}
}
